package com.graduation.project.service.system.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.graduation.project.entity.dto.unit.ListUnitDTO;
import com.graduation.project.entity.dto.UpdateStatusDTO;
import com.graduation.project.entity.dto.unit.SaveOrUpdateUnitDTO;
import com.graduation.project.entity.po.Unit;
import com.graduation.project.entity.vo.unit.ListParentUnitVO;
import com.graduation.project.entity.vo.unit.ListUnitVO;
import com.graduation.project.enums.ResultCodeEnum;
import com.graduation.project.mapper.system.UnitMapper;
import com.graduation.project.service.system.UnitManagementService;
import com.graduation.project.utils.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class UnitManagementServiceImpl extends ServiceImpl<UnitMapper, Unit> implements UnitManagementService {

    @Autowired
    private UnitMapper unitMapper;

    @Override
    public ResultUtil<?> listUnitByCondition(ListUnitDTO input) {
        LambdaQueryWrapper<Unit> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StringUtils.isNotBlank(input.getUnitName()), Unit::getUnitName, input.getUnitName())
                .eq(input.getUnitStatus() != null, Unit::getUnitStatus, input.getUnitStatus());

        List<Unit> units = unitMapper.selectList(lambdaQueryWrapper);

        List<ListUnitVO> unitVOList = units.stream()
                .map(unit -> {
                    ListUnitVO listUnitVO = new ListUnitVO();
                    BeanUtil.copyProperties(unit, listUnitVO);
                    return listUnitVO;
                })
                .collect(Collectors.toList());

        return ResultUtil.Success(ResultCodeEnum.SUCCESS, unitVOList);
    }

    @Override
    public ResultUtil<?> listParentUnit() {
        // 获取单位类型为单位的所有数据
        List<Unit> units = unitMapper.selectList(null);

        List<ListParentUnitVO> listParentUnitVOList = units.stream()
                .map(unit -> {
                    ListParentUnitVO listParentUnitVO = new ListParentUnitVO();
                    BeanUtil.copyProperties(unit, listParentUnitVO);
                    return listParentUnitVO;
                })
                .collect(Collectors.toList());

        return ResultUtil.Success(ResultCodeEnum.SUCCESS, listParentUnitVOList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<?> addUnit(SaveOrUpdateUnitDTO input) {
        if (input.getParentUnitId() != 0) {
            // 判断父级单位的类型是否 不是专业
            Unit unit = unitMapper.selectOne(new LambdaQueryWrapper<Unit>()
                    .select(Unit::getUnitType)
                    .eq(Unit::getId, input.getParentUnitId()));
            if (ObjectUtil.isEmpty(unit)) {
                return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "父级单位不存在");
            }
            if (unit.getUnitType() == 1) {
                return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "父级单位类型错误");
            }
        }
        Unit addUnit = new Unit();
        BeanUtil.copyProperties(input, addUnit, "id");
        // 新增单位
        try {
            unitMapper.insert(addUnit);
        }catch (Exception e) {
            throw new RuntimeException("新增失败");
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "新增成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultUtil<?> updateUnit(SaveOrUpdateUnitDTO input) {
        // 判断修改数据是否存在
        Unit unit = unitMapper.selectOne(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getId, input.getId()));
        if (ObjectUtil.isEmpty(unit)) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "修改数据不存在");
        }
        // 不能修改单位类型
        if (!unit.getUnitType().equals(input.getUnitType())) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "单位类型不一致");
        }
        // 如果修改了父级单位
        if (!unit.getParentUnitId().equals(input.getParentUnitId())) {
            // 判断修改的父级单位类型是否 不是专业
            Unit result = unitMapper.selectOne(new LambdaQueryWrapper<Unit>()
                    .select(Unit::getUnitType)
                    .eq(Unit::getId, input.getParentUnitId()));
            if (ObjectUtil.isEmpty(result)) {
                return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "父级单位不存在");
            }
            if (result.getUnitType() == 1) {
                return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "父级单位类型错误");
            }
        }
        // 修改数据
        BeanUtil.copyProperties(input, unit);
        try {
            unitMapper.updateById(unit);
        }catch (Exception e) {
            throw new RuntimeException("修改失败");
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "修改成功");
    }

    @Override
    public ResultUtil<?> deleteUnit(Long id) {
        if (StringUtils.isBlank(id.toString())) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "参数不能为空");
        }
        // 查询全部单位
        List<Unit> units = unitMapper.selectList(new LambdaQueryWrapper<Unit>()
                .select(
                        Unit::getId,
                        Unit::getParentUnitId,
                        Unit::getUnitType
                ));

        List<Long> idList = new ArrayList<>();
        idList.add(id);
        // 过滤出当前节点的子树,并将id进行扁平化处理
        this.getChildUnitId(units, id, idList);

        // 删除数据
        for (Long a : idList) {
            unitMapper.delete(new LambdaQueryWrapper<Unit>().eq(Unit::getId, a));
        }

        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "删除成功");
    }

    @Override
    public ResultUtil<?> updateUnitStatusById(UpdateStatusDTO input) {
        // 判断当前数据是否存在
        Unit unit = unitMapper.selectOne(new LambdaQueryWrapper<Unit>().eq(Unit::getId, input.getId()));
        if (ObjectUtil.isEmpty(unit)) {
            return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "操作数据不存在");
        }
        List<Long> idList = new ArrayList<>();
        idList.add(input.getId());
        // 如果修改为启用状态：status=0，且当前不是顶级节点
        if (input.getStatus().equals(0) && unit.getParentUnitId() != 0) {
            // 判断其父级状态是否为启用
            Unit result = unitMapper.selectOne(new LambdaQueryWrapper<Unit>()
                    .select(Unit::getUnitStatus)
                    .eq(Unit::getId, unit.getParentUnitId()));
            if (result.getUnitStatus().equals(1)) {
                return ResultUtil.Failed(ResultCodeEnum.FILED.getCode(), "请先启用父级");
            }
        }
        // 如果修改为停用状态：status=1，且当前不是底级节点
        if (input.getStatus().equals(1) && unit.getUnitType() != 1) {
            // 查询全部单位
            List<Unit> units = unitMapper.selectList(new LambdaQueryWrapper<Unit>()
                    .select(
                            Unit::getId,
                            Unit::getParentUnitId,
                            Unit::getUnitType
                    ));
            // 过滤出当前节点的子树,并将id进行扁平化处理
            this.getChildUnitId(units, input.getId(), idList);
        }
        // 修改状态
        for (Long a : idList) {
            unitMapper.update(null, new LambdaUpdateWrapper<Unit>()
                    .set(Unit::getUnitStatus, input.getStatus())
                    .eq(Unit::getId, a));
        }
        return ResultUtil.Success(ResultCodeEnum.SUCCESS.getCode(), "操作成功");
    }

    private List<Long> getChildUnitId(List<Unit> units, Long id, List<Long> idList) {
        for (Unit unit : units) {
            if (id.equals(unit.getParentUnitId())) {
                idList.add(unit.getId());
                if (unit.getUnitType() != 1) {
                    this.getChildUnitId(units, unit.getId(), idList);
                }
            }
        }
        return idList;
    }
}
